#include "bsp_key.h"

#define BSP_KEY_LOG "[bsp_key]"

static pin_t g_key_pin[KEY_MAX_NUM] = {0}; // LED pin

// 定义按键中断回调函数
void (*g_key_Press_Collback[KEY_MAX_NUM])(void) = {0};
void (*g_key_Release_Collback[KEY_MAX_NUM])(void) = {0};

// 按键中断回调函数
static void __bsp_key_isr_callback(pin_t pin, uintptr_t param)
{
    (void)param;

    gpio_level_t level = uapi_gpio_get_val(pin);

    if (pin == g_key_pin[KEY1])
    {
        if (level == GPIO_LEVEL_LOW)
        {
            // osal_printk("%s KEY1 pressed\n", BSP_KEY_LOG);
            if (g_key_Press_Collback[KEY1] != NULL)
            {
                g_key_Press_Collback[KEY1]();
            }
        }
        else if (level == GPIO_LEVEL_HIGH)
        {
            // osal_printk("%s KEY1 release\n", BSP_KEY_LOG);
            if (g_key_Release_Collback[KEY1] != NULL)
            {
                g_key_Release_Collback[KEY1]();
            }
        }
    }
    else if (pin == g_key_pin[KEY2])
    {
        if (level == GPIO_LEVEL_LOW)
        {
            // osal_printk("%s KEY2 pressed\n", BSP_KEY_LOG);
            if (g_key_Press_Collback[KEY2] != NULL)
            {
                g_key_Press_Collback[KEY2]();
            }
        }
        else if (level == GPIO_LEVEL_HIGH)
        {
            // osal_printk("%s KEY2 release\n", BSP_KEY_LOG);
            if (g_key_Release_Collback[KEY2] != NULL)
            {
                g_key_Release_Collback[KEY2]();
            }
        }
    }
    else
    {
        osal_printk("%s unhandled key pin: %d\n", BSP_KEY_LOG, pin);
    }
}

/**
 * @brief  初始化按键设备。
 * @param  [in] key_id 需要初始化的led设备id号， 参考 @ref key_id_t 。
 * @param  [in] pin led设备使用的GPIO引脚， 参考 @ref pin_t 。
 * @retval ERRCODE_SUCC 成功。
 * @retval Other        失败，参考 @ref errcode_t 。
 */
errcode_t bsp_key_init(key_id_t key_id, pin_t pin)
{
    // 检查参数
    if (key_id >= KEY_MAX_NUM)
    {
        osal_printk("%s Invalid Error\n", BSP_KEY_LOG);
        return ERRCODE_INVALID_PARAM;
    }

    // 保存引脚
    g_key_pin[key_id] = pin;

    // 设置引脚模式
    errcode_t ret = ERRCODE_SUCC;
    if (g_key_pin[key_id] == GPIO_04)
    {
        ret = uapi_pin_set_mode(g_key_pin[key_id], PIN_MODE_2);
    }
    else if (g_key_pin[key_id] == GPIO_05)
    {
        ret = uapi_pin_set_mode(g_key_pin[key_id], PIN_MODE_4);
    }
    else
    {
        ret = uapi_pin_set_mode(g_key_pin[key_id], PIN_MODE_0);
    }
    if (ret != ERRCODE_SUCC)
    {
        osal_printk("%s: set key[%d] pin mode failed, ret = %d\n", BSP_KEY_LOG, key_id + 1, ret);
        return ret;
    }

    // 设置引脚方向
    ret = uapi_gpio_set_dir(g_key_pin[key_id], GPIO_DIRECTION_INPUT);
    if (ret != ERRCODE_SUCC)
    {
        osal_printk("%s: set key[%d] pin direction failed, ret = %d\n", BSP_KEY_LOG, key_id + 1, ret);
        return ret;
    }

    // 设置引脚上下拉
    ret = uapi_pin_set_pull(g_key_pin[key_id], PIN_PULL_TYPE_UP);
    if (ret != ERRCODE_SUCC)
    {
        osal_printk("%s: set key[%d] pin pull failed, ret = %d\n", BSP_KEY_LOG, key_id + 1, ret);
        return ret;
    }

    return ERRCODE_SUCC;
}

/**
 * @brief  检测按键状态。
 * @param  [in] key_id 需要检测的按键设备id号， 参考 @ref key_id_t 。
 * @retval 按键状态 成功，参考 @ref key_state_t 。
 * @retval Other        失败，参考 @ref errcode_t 。
 */
errcode_t bsp_key_get_state(key_id_t key_id)
{
    // 检查参数
    if (key_id >= KEY_MAX_NUM)
    {
        osal_printk("%s Invalid Error\n", BSP_KEY_LOG);
        return ERRCODE_INVALID_PARAM;
    }

    return uapi_gpio_get_val(g_key_pin[key_id]);
}

/**
 * @brief  开启按键中断。
 * @param  [in] key_id 需要开启中断的按键设备id号， 参考 @ref key_id_t 。
 * @param  [in] press_callback 按键设备按下时，中断回调函数。不可为空。
 * @param  [in] release_callback 按键设备释放时，中断回调函数。 可以为空。
 * @retval ERRCODE_SUCC 成功。
 * @retval Other        失败，参考 @ref errcode_t 。
 */
errcode_t bsp_key_enable_interrupt(key_id_t key_id, void (*press_callback)(void), void (*release_callback)(void))
{
    // 检查参数
    if (key_id >= KEY_MAX_NUM || press_callback == NULL)
    {
        osal_printk("%s Invalid Error\n", BSP_KEY_LOG);
        return ERRCODE_INVALID_PARAM;
    }

    // 注册中断回调函数
    g_key_Press_Collback[key_id] = press_callback;
    g_key_Release_Collback[key_id] = release_callback;

    // 注册按键中断
    errcode_t ret = uapi_gpio_register_isr_func(g_key_pin[key_id], GPIO_INTERRUPT_DEDGE, __bsp_key_isr_callback);
    if (ret != ERRCODE_SUCC)
    {
        osal_printk("%s: register key[%d] isr failed, ret = %d\n", BSP_KEY_LOG, key_id + 1, ret);
        return ret;
    }

    return ERRCODE_SUCC;
}

/**
 * @brief  关闭按键中断。
 * @param  [in] key_id 需要开启中断的按键设备id号， 参考 @ref key_id_t 。
 * @retval ERRCODE_SUCC 成功。
 * @retval Other        失败，参考 @ref errcode_t 。
 */
errcode_t bsp_key_disable_interrupt(key_id_t key_id)
{
    // 检查参数
    if (key_id >= KEY_MAX_NUM)
    {
        osal_printk("%s Invalid Error\n", BSP_KEY_LOG);
        return ERRCODE_INVALID_PARAM;
    }

    // 去注册中断回调函数
    g_key_Press_Collback[key_id] = NULL;
    g_key_Release_Collback[key_id] = NULL;

    // 去注册按键中断
    errcode_t ret = uapi_gpio_unregister_isr_func(g_key_pin[key_id]);
    if (ret != ERRCODE_SUCC)
    {
        osal_printk("%s: unregister key[%d] isr failed, ret = %d\n", BSP_KEY_LOG, key_id + 1, ret);
        return ret;
    }

    return ERRCODE_SUCC;
}
